package com.restaurantonlineorder.oauth.configure;

import com.restaurantonlineorder.oauth.Perperties.LoginPathProperties;
import com.restaurantonlineorder.oauth.filter.LoginFilter;
import com.restaurantonlineorder.oauth.handler.OauthAccessDeniedHandler;
import com.restaurantonlineorder.oauth.handler.OauthAuthenticationEntryPoint;
import lombok.SneakyThrows;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * @author 熊宇
 * @date 2022/7/20 15:09
 * @description SpringSecurity配置类
 */
@Configuration
@EnableConfigurationProperties(LoginPathProperties.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private AuthenticationSuccessHandler defaultAuthenticationSuccessHandler;

    @Resource
    private AuthenticationFailureHandler defaultAuthenticationFailureHandler;


    @Resource
    private OauthAccessDeniedHandler oauthAccessDeniedHandler;

    @Resource
    private OauthAuthenticationEntryPoint oauthAuthenticationEntryPoint;

    @Resource
    private LoginPathProperties loginPathProperties;


    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    /**
     * 配置AuthenticationManager
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(daoAuthenticationProvider());
    }


    /**
     * 配置一套过滤器链
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(oauthAuthenticationEntryPoint)
                .accessDeniedHandler(oauthAccessDeniedHandler)
                .and()
                .csrf()
                .disable();

        //添加登录认证拦截器
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);


    }


    /**
     * 配置加密器
     *
     * @return
     */
    @Bean
    public BCryptPasswordEncoder bcryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @SneakyThrows
    public LoginFilter loginFilter() {

        LoginFilter loginFilter = new LoginFilter(super.authenticationManager());

        //登录认证路径
        String loginPath = loginPathProperties.getPath();

        //配置LoginFilter 拦截处理路径
        loginFilter.setFilterProcessesUrl(loginPath);

        loginFilter.setAuthenticationSuccessHandler(defaultAuthenticationSuccessHandler);
        loginFilter.setAuthenticationFailureHandler(defaultAuthenticationFailureHandler);
        return loginFilter;
    }

    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder);
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        return daoAuthenticationProvider;
    }


}
